import Task;

class FlashNetworkClient
{
	static var status = new CreepTextField();

	static public var gametodownload = -1;
	static public var baseurl = "";

	static public var timer = new flash.utils.Timer(30);
	
	static public var masterloader : TransactionMasterLoader;
	static public var uploadgame : TransactionUploadGame;
	static public var downloadgame : TransactionDownloadGame;
	static public var downloadnumber : TransactionDownloadNumber;

	public static function start()
	{

		masterloader = new TransactionMasterLoader();
		downloadgame = new TransactionDownloadGame();
		downloadnumber = new TransactionDownloadNumber();
		uploadgame = new TransactionUploadGame();

		masterloader.connect();

		timer.addEventListener(flash.events.TimerEvent.TIMER, dotimer);
		timer.start();

	}

	public static function dotimer(?e : Dynamic)
	{
		if (masterloader.status==Transaction.NOTHING)
		{
			if (uploadgame.status==Transaction.CONNECTING)
				uploadgame.connect();
			if (downloadgame.status==Transaction.CONNECTING)
				downloadgame.connect();
			if (downloadnumber.status==Transaction.CONNECTING)
				downloadnumber.connect();
		}
		else if (masterloader.status==Transaction.CONNECTING)
		{
			masterloader.connect();
		}
	}

}

class Transaction
{

	public var loader : flash.net.URLLoader;

	public static inline var NOTHING = -1;
	public static inline var TRANSFERRING = 0;
	public static inline var CONNECTING = 1;

	public var status : Int;

	function ondone () {}
	function onconnect () {}
	
	public var timeoutframes : Int;
	public var maxtimeout : Int;
	public var timeouts : Int;

	public function new()
	{
		status = NOTHING;
		timeoutframes = 0;
		timeouts = 0;
		maxtimeout = 30;
		setuploader();
	}

	public function setuploader()
	{
		loader = new flash.net.URLLoader();
		
		loader.addEventListener(flash.events.Event.COMPLETE,
			done);
		loader.addEventListener(flash.events.IOErrorEvent.IO_ERROR,
			error);
		loader.addEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR,
			error);
		loader.addEventListener(flash.events.ProgressEvent.PROGRESS,
			progress);		
		FlashNetworkClient.timer.addEventListener(flash.events.TimerEvent.TIMER,
			timeouttest);		
	}
	
	public function unsetuploader()
	{
		try
		{
			loader.close();
		}
		catch (d:Dynamic) {}
		
		loader.removeEventListener(flash.events.Event.COMPLETE,
			done);
		loader.removeEventListener(flash.events.IOErrorEvent.IO_ERROR,
			error);
		loader.removeEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR,
			error);
		loader.removeEventListener(flash.events.ProgressEvent.PROGRESS,
			progress);		
		FlashNetworkClient.timer.removeEventListener(flash.events.TimerEvent.TIMER,
			timeouttest);				
	}

	function error(?e : Dynamic)
	{
		status = CONNECTING;
	}

	public function request(?e : Dynamic)
	{
		FlashClient.setmsgdisplay("Connecting.");		
		status = CONNECTING;
		timeoutframes = 0;
		FlashNetworkClient.dotimer();
	}

	function progress(?e : Dynamic)
	{
		FlashClient.setmsgdisplay("Transferring.");		
		timeoutframes = 0;
	}

	function timeouttest(?e : Dynamic)
	{
		if (status!=NOTHING)
		{
			timeoutframes += 1;
			if (timeoutframes > maxtimeout)
			{
				FlashClient.setmsgdisplay("Timed out.");		
				maxtimeout = Std.int(maxtimeout * 1.2);
				timeoutframes = 0;
				timeouts += 1;
				unsetuploader();
				setuploader();
				status = CONNECTING;
			}
		}
	}

	public function connect(?e : Dynamic)
	{
		onconnect();
		status = TRANSFERRING;
		timeoutframes = 0;
	}

	public function done(?e : Dynamic)
	{
		timeouts = 0;
		FlashClient.setmsgdisplay("Finished.");		
		ondone();
		status = NOTHING;
		maxtimeout = 30;
	}
	
}

class TransactionMasterLoader extends Transaction
{
	public function new()
	{
		super();
	}
	
	function onconnect()
	{
		loader.load( new flash.net.URLRequest("http://spacecreeps.com/servers") );			
		FlashClient.setmsgdisplay("Getting master list ("+Std.string(timeouts)+")");
	}
	
	function ondone()
	{
		// here is a puzzle: remove the following line and it never finishes start?
		FlashClient.setmsgdisplay("Got master list");
		
		var str = loader.data;
		var lines : Array<String> = str.split("\n");
		var index = Std.int(Math.random()*lines.length);
		
		FlashNetworkClient.baseurl = "http://"+lines[index]+"/creepweb.n";

		status=Transaction.NOTHING;
		FlashNetworkClient.dotimer();

	}
		
}

class TransactionDownloadNumber extends Transaction
{
	public function new()
	{
		super();
	}
	
	function onconnect()
	{
		var req = new flash.net.URLRequest(FlashNetworkClient.baseurl+"/?cmd=dailygame");
		FlashClient.setmsgdisplay("Loading daily game. ("+Std.string(timeouts)+")");
		loader.load(req);
	}
	
	function ondone()
	{
		FlashClient.setmsgdisplay("Got today's game.");
		var result = 
			loader.data;
		for (n in 0...result.length)
		{
			if 
			(n<FlashClient.mainmenu.customgameinput.length)
			FlashClient.mainmenu.customgameinput[n].text=
				result.charAt(n);						
		}
		FlashClient.todaysgame = 
			Std.parseInt(result.toString());				
	}
		
}

class TransactionDownloadGame extends Transaction
{
	public function new()
	{
		super();
	}
	
	function onconnect()
	{
		FlashClient.setmsgdisplay("Downloading recording. ("+Std.string(timeouts)+")");
		loader.load(
			new flash.net.URLRequest(FlashNetworkClient.baseurl+"/?cmd=getrecord&id="+
				Std.string(FlashNetworkClient.gametodownload)));
	}
	
	function ondone()
	{
		var str = loader.data;
		var arrayresult : Array<Dynamic> = 
		haxe.Unserializer.run(str);
						
		var result = new Recording();
		result.assign(haxe.Unserializer.run(arrayresult[0]),arrayresult[1],arrayresult[2],arrayresult[3]);
										
		if (result!=null)
		{
			try
			{
			  FlashClient.setmsgdisplay("Game "+result.seed+"\nby "+result.name+"\nof "+result.group);
			  FlashClient.restartgame(-1, result);
			}
			catch (d : Dynamic) 
			{FlashClient.setmsgdisplay(
				"Invalid game or malformed recording!");
				FlashClient.setmsgdisplay(str);
			}						
		}
		else
		{
			FlashClient.setmsgdisplay("Game is locked or"+
			"nonexistent.");
		}
	}
		
}

class TransactionUploadGame extends Transaction
{
	public function new()
	{
		super();
	}
	
	function onconnect()
	{
		var req = new flash.net.URLRequest(FlashNetworkClient.baseurl+"/?cmd=storerecord");
		req.method = flash.net.URLRequestMethod.POST;
		var vars = new flash.net.URLVariables();

		var rec = new Recording(); 
		rec.assign(rules.RulesAPI.record, FlashClient.mainmenu.nametext_submit.text, 
					FlashClient.mainmenu.grouptext_submit.text, FlashClient.todaysgame);
		vars.data = haxe.Serializer.run(rec);
		req.data = vars;
		loader.load(req);
	}
	
	function ondone()
	{
		var z : Array<String> = loader.data.split(" ");
		if (loader.data=="OK")
			FlashClient.setmsgdisplay("Score sent!");
		else
			FlashClient.setmsgdisplay("Uh oh:\n Recording had errors\n and won't be stored.");
		FlashClient.mainmenu.switchtotitlemenu();		
	}
		
}
